package app.server.project.main.service.service.luck;

import app.server.project.core.constants.Def;
import app.server.project.main.service.db.dao.user.SolanaInfoDao;
import app.server.project.main.service.db.dao.user.SolanaSlotDao;
import app.server.project.main.service.db.entity.user.SolanaSlotEntity;
import app.server.project.main.service.dto.solanainfo.CurrentSlotResp;
import app.server.project.main.service.dto.solanainfo.InfoReq;
import app.server.project.main.service.dto.solanainfo.SlotResp;
import app.server.project.main.service.service.upay.tron.USDTRateService;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
@Slf4j
public class SolanaInfoService {

    private final static int Max = 3600;
    private final static int Solana_Slot = 1;
    private final static String BaseUrl = "https://api.mainnet-beta.solana.com";
    private final SolanaInfoDao solanaInfoDao;
    private final SOLLuckService soLLuckService;
    private final SOLRateService solRateService;
    private final USDTRateService usdRateService;
    private final SolanaSlotDao solanaSlotDao;

    private long currentSlot = 0;
    private long lastSlot = 0;

    //开始初始化solana链配置信息
    private void initSolanaInfo() {
        this.solanaSlotDao.getAll(Solana_Slot);
        var solanaInfoEntity = solanaInfoDao.getSolanaInfoData(Solana_Slot);
        if (solanaInfoEntity.getNum() == 0) {
            solanaInfoEntity.setNum(getSolanaNetSlot());
        }
        this.currentSlot = solanaInfoEntity.getNum();
    }

    @Async(Def.CommonPool)
    @EventListener(ApplicationReadyEvent.class)
    public void init() {
        //this.initSolanaInfo();
        this.lastSlot = this.getSolanaNetSlot();
        this.soLLuckService.init();
        this.solRateService.init();
        this.usdRateService.init();
    }

    private long getSolanaNetSlot() {
        String body = JSONUtil.toJsonStr(InfoReq.ofCurrentSlot());
        String jsonRet = HttpUtil.post(BaseUrl, body);
        var resp = JSONUtil.toBean(jsonRet, CurrentSlotResp.class);
        return resp.getResult();
    }


    private void addSlot(SlotResp resp, long slot) {
        var lst = this.solanaSlotDao.getAll(Solana_Slot);
        //系统自己的时间
        resp.getResult().setBlockTime(System.currentTimeMillis() / 1000);
        if (lst.size() >= Max) {
            //淘汰掉最后的数据
            var last = lst.get(lst.size() - 1);
            last.setSlot(slot);
            last.setBlockTime(resp.getResult().getBlockTime());
            last.setBlockHash(resp.getResult().getBlockhash());
            lst.remove(last);
            lst.add(0, last);
        } else {
            var solanaSlotEntity = SolanaSlotEntity.of(IdUtil.getSnowflakeNextId());
            solanaSlotEntity.setSlot(slot);
            solanaSlotEntity.setBlockTime(resp.getResult().getBlockTime());
            solanaSlotEntity.setBlockHash(resp.getResult().getBlockhash());
            lst.add(0, solanaSlotEntity);
        }
    }


    @Scheduled(fixedDelay = 1000)
    public void doLuck() {
        if (this.soLLuckService.IsEmpty() && this.solRateService.IsEmpty() && this.usdRateService.IsEmpty()) return;
        var current = this.getSolanaNetSlot();
        //初始化可能失败
        if (this.lastSlot == 0) {
            //重新生成区块号
            this.lastSlot = current;
            return;
        }
        //检查是否是上次区块号
        if (current == this.lastSlot) return;
        //拉取最新slot数据
        String body = JSONUtil.toJsonStr(InfoReq.ofGetBlock(current));
        String jsonRet = HttpUtil.post(BaseUrl, body);
        if (StrUtil.isBlank(jsonRet)) return;
        if (!JSONUtil.isTypeJSON(jsonRet)) {
            log.error("json解析失败:{}", jsonRet);
            return;
        }
        var httpResp = JSONUtil.toBean(jsonRet, SlotResp.class);
        if (httpResp.getResult() == null) return;
        this.lastSlot = current;
        //初始化数据
        httpResp.setSlot(current);
        httpResp.getResult().setBlockTime(System.currentTimeMillis() / 1000);
        //处理中奖逻辑
        this.soLLuckService.matchOrder(httpResp);
        this.solRateService.matchOrder(httpResp);
        this.usdRateService.matchOrder(httpResp);

    }
}
